//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "pmodule.h"
#include "pcentral.h"
#include <aura.h>

#define Lock    do { \
                    AuraCriticalSection_Enter(m_hLock); \
                } while(0)

#define Unlock  do { \
                    AuraCriticalSection_Leave(m_hLock); \
                } while(0)

#define REMOTE_PROCESS_ALREADY_EXITED() (NULL == m_pProxy)
#define REMOTE_PROCESS_JUST_EXITED(ec)  (E_PROCESS_ALREADY_EXITED == ec)

CPseudoModule::~CPseudoModule()
{
    if (NULL != m_hLock) {
        AuraCriticalSection_Destroy(m_hLock);
        m_hLock = NULL;
    }
}

ECode CPseudoModule::Initialize()
{
    return (ECode)AuraCriticalSection_Create(&m_hLock);
}

PInterface CPseudoModule::Probe(
        /* [in]  */ REIID riid)
{
    if (riid == EIID_IInterface) {
        return (IInterface *)(IModule *)this;
    }
    else if (riid == EIID_IModule) {
        return (IModule *)this;
    }
    else if (riid == EIID_CLASS_INFO) {
        return (PInterface)&ECLSID_CModule;
    }
    else if (riid == EIID_INTERFACE_INFO) {
        return (PInterface) &EIID_IModule;
    }

    return NULL;
}

UInt32 CPseudoModule::AddRef()
{
    Int32 nRefs = m_cRef.Increment();

    return (UInt32)nRefs;
}

UInt32 CPseudoModule::Release()
{
    Int32 nRefs = m_cRef.Decrement();

    if (0 == nRefs) {
        PseudoObject::S_Delete(PseudoObjectType_Module, this);
        if (NULL != m_pProxy) {
            m_pProxy->Release();
            m_pProxy = NULL;
        }
        else {
            // TODO :
        }
        delete this;
    }

    return (UInt32)nRefs;
}

ECode CPseudoModule::Aggregate(
        /* [in] */ AggrType aggrType,
        /* [in] */ PInterface pObject)
{
    return E_NOT_IMPLEMENTED;
}

ECode CPseudoModule::GetDomain(
        /* [out] */ PInterface *ppObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CPseudoModule::GetBaseAddress(
        /* [out] */ Address * pBase)
{
    ECode ec = NOERROR;

    Lock;
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->GetBaseAddress(pBase);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock;

    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock;

    return E_PROCESS_ALREADY_EXITED;
}

ECode CPseudoModule::GetEntryPointAddress(
        /* [out] */ Address * pDllMainStartup)
{
    ECode ec = NOERROR;

    Lock;
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->GetEntryPointAddress(pDllMainStartup);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock;

    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock;

    return E_PROCESS_ALREADY_EXITED;
}

ECode CPseudoModule::GetMemorySize(
        /* [out] */ MemorySize * pSize)
{
    ECode ec = NOERROR;

    Lock;
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->GetMemorySize(pSize);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock;

    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock;

    return E_PROCESS_ALREADY_EXITED;
}

ECode CPseudoModule::GetName(
        /* [out] */ WStringBuf * name)
{
    ECode ec = NOERROR;

    Lock;
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->GetName(name);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock;

    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock;

    return E_PROCESS_ALREADY_EXITED;
}

ECode CPseudoModule::GetFullPath(
        /* [out] */ WStringBuf * name)
{
    ECode ec = NOERROR;

    Lock;
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->GetFullPath(name);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock;

    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock;

    return E_PROCESS_ALREADY_EXITED;
}

ECode CPseudoModule::GetProcAddressByName(
        /* [in] */ AString Name,
        /* [out] */ Address * pAddress)
{
    // TODO:
    assert(0);
    return E_NOT_IMPLEMENTED;
}

ECode CPseudoModule::GetProcAddressByOrdinal(
        /* [in] */ Int32 ordinal,
        /* [out] */ Address * pAddress)
{
    // TODO:
    assert(0);
    return E_NOT_IMPLEMENTED;
}

ECode CPseudoModule::GetResourceSection(
        /* [out] */ Address * pAddress)
{
    // TODO:
    assert(0);
    return E_NOT_IMPLEMENTED;
}

ECode CPseudoModule::GetSectionByName(
        /* [in] */ AString Name,
        /* [out] */ Address * pAddress)
{
    // TODO:
    assert(0);
    return E_NOT_IMPLEMENTED;
}

ECode CPseudoModule::FindResource(
        /* [in] */ WString wsName,
        /* [in] */ WString wsType,
        /* [out] */ Address * pAddress,
        /* [out] */ MemorySize * pSize)
{
    // TODO:
    assert(0);
    return E_NOT_IMPLEMENTED;
}

ECode CPseudoModuleFactory::CreateObject(
    /* [out] */ PseudoObject ** ppPseudoObject)
{
    CPseudoModule * pModule = NULL;
    ECode ec = NOERROR;

    assert(NULL != ppPseudoObject);
    pModule = new CPseudoModule(m_processId, m_pProxy);
    if (NULL == pModule) {
        return E_OUT_OF_MEMORY;
    }

    ec = pModule->Initialize();
    if (FAILED(ec)) {
        delete pModule;
        pModule = NULL;
    }
    pModule->AddRef();
    *ppPseudoObject = pModule;

    return NOERROR;
}
